package com.ld.poetry.utils;

import com.ld.poetry.handle.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Objects;


@Slf4j
public class FileUploadUtils {

	// 默认上传的地址
	private static final String defaultBaseDir = "sara-resources";
	// 默认的文件名最大长度
	public static final int DEFAULT_FILE_NAME_LENGTH = 200;
	public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };
	public static final String[] FLASH_EXTENSION = { "swf", "flv" };
	public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
			"asf", "rm", "rmvb" };
	public static final String[] DEFAULT_ALLOWED_EXTENSION = {
			// 图片
			"bmp", "gif", "jpg", "jpeg", "png",
			// word excel powerpoint
			"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
			// 压缩文件
			"rar", "zip", "gz", "bz2",
			//音频文件
			"swf","mp3",
			// pdf
			"pdf"
	};

	private static String SYSTEM = "";

	static {
		SYSTEM = System.getProperty("os.name");
	}


	public static String upload(String uploadDir,
								MultipartFile file,
								long maxSize) throws IOException{
		return upload(uploadDir,file,DEFAULT_ALLOWED_EXTENSION,maxSize);
	}

	public static String upload(String uploadDir,
								MultipartFile file,
								String[] allowedExtension,
								long maxSize) throws IOException{
		if(null == file){
			throw new BaseException(-1,"请上传您的文件！");
		}

		assertAllowed(file, allowedExtension, maxSize);

		String filename = extractFilename(file, defaultBaseDir);

		File desc = getAbsoluteFile(uploadDir, filename);

		file.transferTo(desc);

		return filename;
	}

	private static File getAbsoluteFile(String uploadDir, String filename) throws IOException {

		uploadDir = FilenameUtils.normalizeNoEndSeparator(uploadDir);

		uploadDir = SYSTEM.toLowerCase().contains("windows") ? "D:" + uploadDir : uploadDir;

		File desc = new File(uploadDir + "/" + filename);

		if (!desc.getParentFile().exists()) {
			boolean mkdirs = desc.getParentFile().mkdirs();
			log.info("is mkdirs ? =====> {}",mkdirs);
		}
		if (!desc.exists()) {
			boolean newFile = desc.createNewFile();
			log.info("is new file ? =====> {}",newFile);
		}
		return desc;
	}

	public static void assertAllowed(MultipartFile file, long maxSize){
		assertAllowed(file,DEFAULT_ALLOWED_EXTENSION,maxSize);
	}

	public static void assertAllowed(MultipartFile file, String[] allowedExtension, long maxSize){
		int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();

		if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
			throw new BaseException(-1,"文件名称太长！");
		}

		//获取后缀
		String extension = FilenameUtils.getExtension(file.getOriginalFilename());

		if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
			if (allowedExtension == IMAGE_EXTENSION) {
				throw new BaseException(-1,"请选择图片文件进行上传！");
			} else if (allowedExtension == FLASH_EXTENSION) {
				throw new BaseException(-1,"请选择flash文件进行上传！");
			} else if (allowedExtension == MEDIA_EXTENSION) {
				throw new BaseException(-1,"请选择媒体文件进行上传！");
			} else {
				throw new BaseException(-1,"不支持的文件类型！");
			}
		}

		long size = file.getSize();
		if (maxSize != -1 && size > maxSize) {
			throw new BaseException(-1,"文件太大！请重新选择！");
		}
	}

	public static String extractFilename(MultipartFile file, String baseDir) {
		String filename = file.getOriginalFilename();

		assert filename != null;
		int slashIndex = filename.indexOf("/");

		if (slashIndex >= 0) {
			filename = filename.substring(slashIndex + 1);
		}

		filename = baseDir + "/" + datePath() + "/" + System.currentTimeMillis() + "."
				+ getExtensionName(filename);

		return filename;
	}

	public static String getExtensionName(String filename) {
		if ((filename != null) && (filename.length() > 0)) {
			int dot = filename.lastIndexOf('.');
			if ((dot > -1) && (dot < (filename.length() - 1))) {
				return filename.substring(dot + 1);
			}
		}
		return filename;
	}

	public static boolean isAllowedExtension(String extension, String[] allowedExtension) {
		for (String str : allowedExtension) {
			if (str.trim().equalsIgnoreCase(extension.trim())) {
				return true;
			}
		}
		return false;
	}

	private static String datePath() {
		Date now = new Date();
		return DateFormatUtils.format(now, "yyyy/MM/dd");
	}

	/**
	 * java计算文件32位md5值
	 * @param fis 输入流
	 */
	public static String md5HashCode32(InputStream fis) {
		try {
			byte[] md5Bytes  = getMD5Bytes(fis);
			StringBuilder hexValue = new StringBuilder();

			 //* 如果小于16，那么val值的16进制形式必然为一位，
			 //* 因为十进制0,1...9,10,11,12,13,14,15 对应的 16进制为 0,1...9,a,b,c,d,e,f;
			 //* 此处高位补0。
			for (byte md5Byte : md5Bytes) {
				int val = ((int) md5Byte) & 0xff;//解释参见最下方
				if (val < 16) {
					//* 如果小于16，那么val值的16进制形式必然为一位，
					//* 因为十进制0,1...9,10,11,12,13,14,15 对应的 16进制为 0,1...9,a,b,c,d,e,f;
					//* 此处高位补0。
					hexValue.append("0");
				}
				//这里借助了Integer类的方法实现16进制的转换
				hexValue.append(Integer.toHexString(val));
			}
			return hexValue.toString();
		} catch (Exception e) {
			log.error("md5HashCode32 error",e);
			throw new BaseException(-1,"检查文件Hash失败！");
		}
	}



	public static byte[] getMD5Bytes(InputStream fis) throws IOException, NoSuchAlgorithmException {
		//拿到一个MD5转换器,如果想使用SHA-1或SHA-256，则传入SHA-1,SHA-256
		MessageDigest md = MessageDigest.getInstance("MD5");

		//分多次将一个文件读入，对于大型文件而言，比较推荐这种方式，占用内存比较少。
		byte[] buffer = new byte[1024];
		int length;
		while ((length = fis.read(buffer, 0, 1024)) != -1) {
			md.update(buffer, 0, length);
		}
		fis.close();

		//转换并返回包含16个元素字节数组,返回数值范围为-128到127
		return md.digest();
	}









}
